//  这句话用来编程时自动提示，运行时需要注释掉！
//import * as BABYLON from '@babylonjs/core';

var canvas = document.getElementById("renderCanvas");

var startRenderLoop = function (engine, canvas) {
  engine.runRenderLoop(function () {
    if (sceneToRender && sceneToRender.activeCamera) {
      sceneToRender.render();
    }
  });
};

var engine = null;
var scene = null;
var sceneToRender = null;
var createDefaultEngine = function () {
  return new BABYLON.Engine(canvas, true, {
    preserveDrawingBuffer: true,
    stencil: true,
    disableWebGL2Support: false,
  });
};


//  创建场景（相关代码都在此处）
var createScene = function () {
  // This creates a basic Babylon Scene object (non-mesh)
  var scene = new BABYLON.Scene(engine);

  //  创建相机
  var camera = new BABYLON.ArcRotateCamera("camera", 0, 1.2, 5, BABYLON.Vector3.Zero());
  camera.attachControl(canvas, true);

  //  创建灯光
  var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0));

  //  显示坐标轴
  showAxis(6, scene);

  //  导入村庄
  BABYLON.SceneLoader.ImportMeshAsync("", "https://assets.babylonjs.com/meshes/", "village.glb");

  // 撞击盒子(只显示线框)
  const hitBox = BABYLON.MeshBuilder.CreateBox("carbox", { width: 0.5, height: 0.6, depth: 5 }, scene);
  const wireMat = new BABYLON.StandardMaterial("wireMat", scene);
  wireMat.wireframe = true;
  hitBox.material = wireMat;
  hitBox.position = new BABYLON.Vector3(3.1, 0.3, -5);

  //  导入汽车,汽车走直线，最后停顿一下。
  let carReady = false;

  BABYLON.SceneLoader.ImportMeshAsync("", "https://assets.babylonjs.com/meshes/", "car.glb").then(() => {
    const car = scene.getMeshByName("car");
    carReady = true;
    car.rotation = new BABYLON.Vector3(Math.PI / 2, 0, -Math.PI / 2);
    car.position.y = 0.16;
    car.position.x = -3;
    car.position.z = 8;

    const animCar = new BABYLON.Animation("carAnimation", "position.z", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

    const carKeys = [{
      frame: 0,
      value: 8
    }, {
      frame: 150,
      value: -7
    },
    {
      frame: 200,
      value: -7
    }];

    animCar.setKeys(carKeys);

    car.animations = [];
    car.animations.push(animCar);

    scene.beginAnimation(car, 0, 200, true);
  });


  const walk = function (turn, dist) {
    this.turn = turn;
    this.dist = dist;
  }
  //  走的距离和旋转角度
  const track = [];
  track.push(new walk(Math.PI, 2.5));
  track.push(new walk(0, 5));
  const initPos = new BABYLON.Vector3(1.5, 0, -6.9);

  //  导入Dude人(材质加载不成功)
  BABYLON.SceneLoader.ImportMeshAsync("him", "/Collision/scenes/", "Dude.babylon", scene).then((result) => {


    //  获取人,并设置人大小、位置、旋转
    const dude = result.meshes[0];
    dude.scaling = new BABYLON.Vector3(0.008, 0.008, 0.008);

    dude.position = initPos;
    dude.rotate(BABYLON.Axis.Y, BABYLON.Tools.ToRadians(-90), BABYLON.Space.LOCAL);
    const startRotation = dude.rotationQuaternion.clone();

    //  播放动画
    scene.beginAnimation(result.skeletons[0], 0, 100, true, 1.0);

    //  初始化球的位置
    let distance = 0.0;
    const step = 0.015;
    let idx = 0;
    //  通过scene.onBeforeRender事件，在每次渲染前更新track
    scene.onBeforeRenderObservable.add(() => {

      if(carReady){
        //  人没有与hixBox相交，但是车与hitBox相交
        if(!dude.getChildren()[1].intersectsMesh(hitBox) &&
        scene.getMeshByName("car").intersectsMesh(hitBox)){
          return;
        }
      }

      //  （往前走）
      dude.movePOV(0, 0, step);
      //  更新距离
      distance += step;

      //  如果距离大于当前track的长度，则旋转球，并更新idx
      if (distance > track[idx].dist) {
        dude.rotate(BABYLON.Axis.Y, track[idx].turn, BABYLON.Space.LOCAL);
        idx++;
        //  如果idx超出范围，则重置位置、距离、旋转
        idx = idx % track.length;
        if (idx === 0) {
          distance = 0;
          dude.position = initPos;
          dude.rotationQuaternion = startRotation.clone();
        }
      }

    });

  });

  return scene;
};



//  创建文字平面
const makeTextPlane = (text, color, size) => {
  const dynamicTexture = new BABYLON.DynamicTexture("dynamicTexture", 50, scene, true);
  dynamicTexture.hasAlpha = true;
  dynamicTexture.drawText(text, 5, 40, "bold 36px Arial", color, "transparent", true);

  const plane = BABYLON.MeshBuilder.CreatePlane("plane", { size: size, updatable: true }, scene);
  plane.material = new BABYLON.StandardMaterial("planeMat", scene);
  plane.material.backFaceCulling = false;
  plane.material.specularColor = new BABYLON.Color3(0, 0, 0);
  plane.material.diffuseTexture = dynamicTexture;
  return plane;
}

const showAxis = (length, scene) => {

  //  创建坐标轴x
  const xAxis = BABYLON.MeshBuilder.CreateLines("xAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(length, 0, 0),
      new BABYLON.Vector3(length * 0.95, 0.1, 0), new BABYLON.Vector3(length, 0, 0),
      new BABYLON.Vector3(length * 0.95, -0.1, 0)]
    }, scene);
  xAxis.color = new BABYLON.Color3(1, 0, 0);
  const xText = makeTextPlane("X", "red", length / 10.0);
  xText.position = new BABYLON.Vector3(length * 0.95, -0.05 * length, 0);

  //  创建坐标轴y
  const yAxis = BABYLON.MeshBuilder.CreateLines("yAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, length, 0),
      new BABYLON.Vector3(-0.1, length * 0.95, 0), new BABYLON.Vector3(0, length, 0),
      new BABYLON.Vector3(0.1, length * 0.95, 0)]
    }, scene);
  yAxis.color = new BABYLON.Color3(0, 1, 0);
  const yText = makeTextPlane("Y", "green", length / 10.0);
  yText.position = new BABYLON.Vector3(0.05 * length, length * 0.95, 0);

  //  创建坐标轴z
  const zAxis = BABYLON.MeshBuilder.CreateLines("zAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 0, length),
      new BABYLON.Vector3(0, -0.1, length * 0.95), new BABYLON.Vector3(0, 0, length),
      new BABYLON.Vector3(0, 0.1, length * 0.95)]
    }, scene);
  zAxis.color = new BABYLON.Color3(0, 0, 1);
  const zText = makeTextPlane("Z", "blue", length / 10.0);
  zText.position = new BABYLON.Vector3(0.05 * length, 0.05 * length, length * 0.95);
}


const localAxis = (length, scene) => {

  //  创建坐标轴x
  const xAxis = BABYLON.MeshBuilder.CreateLines("local_xAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(length, 0, 0),
      new BABYLON.Vector3(length * 0.95, 0.1, 0), new BABYLON.Vector3(length, 0, 0),
      new BABYLON.Vector3(length * 0.95, -0.1, 0)]
    }, scene);
  xAxis.color = new BABYLON.Color3(1, 0, 0);

  //  创建坐标轴y
  const yAxis = BABYLON.MeshBuilder.CreateLines("local_yAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, length, 0),
      new BABYLON.Vector3(-0.1, length * 0.95, 0), new BABYLON.Vector3(0, length, 0),
      new BABYLON.Vector3(0.1, length * 0.95, 0)]
    }, scene);
  yAxis.color = new BABYLON.Color3(0, 1, 0);

  //  创建坐标轴z
  const zAxis = BABYLON.MeshBuilder.CreateLines("local_zAxis",
    {
      points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 0, length),
      new BABYLON.Vector3(0, -0.1, length * 0.95), new BABYLON.Vector3(0, 0, length),
      new BABYLON.Vector3(0, 0.1, length * 0.95)]
    }, scene);
  zAxis.color = new BABYLON.Color3(0, 0, 1);

  //  合并坐标轴(TransformNode不渲染)
  const local_origion = new BABYLON.TransformNode("local_origion", scene);

  local_origion.addChild(xAxis);
  local_origion.addChild(yAxis);
  local_origion.addChild(zAxis);

  return local_origion;
}



//================================================

window.initFunction = async function () {
  var asyncEngineCreation = async function () {
    try {
      return createDefaultEngine();
    } catch (e) {
      console.log(
        "the available createEngine function failed. Creating the default engine instead"
      );
      return createDefaultEngine();
    }
  };

  window.engine = await asyncEngineCreation();
  if (!engine) throw "engine should not be null.";
  startRenderLoop(engine, canvas);
  window.scene = createScene();
};
initFunction().then(() => {
  sceneToRender = scene;
});

// Resize
window.addEventListener("resize", function () {
  engine.resize();
});